//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.Provenance.Controls.Presenter
{
    using System;
    using Microsoft.Research.Provenance.Controls.View;
    using Microsoft.Practices.Unity;
    using Microsoft.Research.ProvenanceCommon.Model;
    using Microsoft.Research.ProvenanceCommon;
    using Microsoft.Research.ProvenanceInterfaces;
    using Microsoft.Research.DataLayer;
    using Microsoft.Research.Provenance.ProvenanceDataService;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows.Input;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;

    /// <summary>
    /// Presentation logic for displaying required inputs of a Workflow.
    /// </summary>
    public class WorkflowInputPresenter : IDisposable, INotifyPropertyChanged
    {
        /// <summary>
        /// Get InputProperties
        /// </summary>
        public ObservableCollection<ActivityProperty> InputProperties { get; private set; }

        /// <summary>
        /// Get WorkFlowSummaryView
        /// </summary>
        public WorkflowInputView View { get; private set; }

        /// <summary>
        /// The command displays Data products.
        /// </summary>
        public ICommand GetWorkflowRequiredInputs { get; private set; }

        /// <summary>
        /// This is to check whether the view is updated or not.
        /// </summary>
        public bool IsUpdated { get; private set; }

        /// <summary>
        /// This is used to set the expanding behaviour of the view.
        /// </summary>
        private bool isExpanded;

        /// <summary>
        /// Gets or sets the IsExpanded property.
        /// </summary>
        public bool IsExpanded
        {
            get
            {
                return this.isExpanded;
            }
            set
            {
                this.isExpanded = value;
                this.OnNotifyPropertyChanged("IsExpanded");
            }
        }

        /// <summary>
        /// The unity container instance.
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Inidicates whether data is not present.
        /// </summary>
        private bool doesNotContainItems;

        /// <summary>
        /// Gets whether data is not present.
        /// </summary>
        public bool DoesNotContainItems
        {
            get
            {
                return this.doesNotContainItems;
            }
            private set
            {
                this.doesNotContainItems = value;
                this.OnNotifyPropertyChanged("DoesNotContainItems");
            }
        }

        /// <summary>
        /// Inidicates whether data is present.
        /// </summary>
        private bool containItems;

        /// <summary>
        /// Gets whether data is present.
        /// </summary>
        public bool ContainItems
        {
            get
            {
                return this.containItems;
            }
            private set
            {
                this.containItems = value;
                this.DoesNotContainItems = !this.ContainItems;
                this.OnNotifyPropertyChanged("ContainItems");
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="container">IUnityContainer</param>
        /// <param name="view">WorkFlowInputView</param>
        public WorkflowInputPresenter(IUnityContainer container, WorkflowInputView view)
        {
            this.container = container;
            this.View = view;
            this.GetWorkflowRequiredInputs = new DelegateCommand<object>(p => { this.OnGetWorkflowRequiredInputs(); });

            this.InputProperties = new ObservableCollection<ActivityProperty>();
            this.View.Presenter = this;
        }

        /// <summary>
        /// This function is used to get workflow required inputs.
        /// </summary>
        private void OnGetWorkflowRequiredInputs()
        {
            this.InputProperties.Clear();
            try
            {
                Collection<ActivityProperty> tempList = this.container.Resolve<DataRetriever>().GetWorkflowInputs();
                foreach (ActivityProperty property in tempList)
                {
                    this.InputProperties.Add(property);
                }

                this.ContainItems = this.InputProperties.Count > 0;

                this.IsUpdated = true;
            }
            catch (TridentCustomException ex)
            {
                TridentMessageBox.ShowTridentErrorMessageBox(ex.Message);
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(exp);
            }
        }

        #region IDisposable Members

        /// <summary>
        /// Clears the collection and View Object
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// nullify and Disposes the object 
        /// </summary>
        /// <param name="disposing"></param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.container.Dispose();
                this.InputProperties = null;
                this.View = null;
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Event for property change.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raise property changed eventargs.
        /// </summary>
        /// <param name="changeProperty">Property anme.</param>
        private void OnNotifyPropertyChanged(string changeProperty)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(changeProperty));
            }
        }

        #endregion
    }
}
